<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>涨停时间轴</title>
    <style>
        /* 完整样式表 */
        body {
            font-family: "Microsoft YaHei", sans-serif;
            margin: 0px;
            background: #000;
            color: #fff;
            padding-top: 90px;
        }
        .controls {
            display: flex;
            flex-direction: column;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            background: #000;
            padding: 2px;
            z-index: 1000;
            box-shadow: 0 2px 5px rgba(0,0,0,0.5);
        }
        .market-overview {
            width: 100%;
            padding: 2px 0;
            border-bottom: 1px solid #333;
            margin-bottom: 1px;
        }
        .market-row {
            display: flex;
            justify-content: center;
            flex-wrap: wrap;
            font-size: 14px;
            line-height: 1.5;
        }
        .stats-bar {
            padding: 1px 2px;
            background: #222;
            display: flex;
            flex-direction: column;
            font-size: 14px;
            display: flex;
            gap: 5px;
            border-bottom: 1px solid #333;
        }

        .market-row span {
            margin: 0 8px;
            color: #fff;
        }
        .market-row .red { color: #ff0000; }
        .market-row .green { color: #00ff00; }
        .market-row .white { color: #ffffff; }
        .market-row .highlight { color: #ffd700; }
        .market-row .blue { color: #00bfff; }
        .original-controls {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 2px;
            padding-top: 2px;
        }
        .type-label {
            color: #ffd700;
            font-size: 18px;
            margin-right: 2px;
            white-space: nowrap;
        }
        #cztCount { color: #00ff00; font-size: 0.8em; margin-left: 1px; }
        #ztCount { color: #ff0000; font-size: 0.8em; margin-left: 1px; }
        .date-nav {
            display: flex;
            align-items: center;
            background: #333;
            border-radius: 6px;
            padding: 1px;
        }
        .date-btn {
            background: none;
            border: none;
            color: #ffd700;
            font-size: 18px;
            width: 26px;
            height: 26px;
            cursor: pointer;
            border-radius: 4px;
        }
        .date-btn:hover { background: rgba(255,215,0,0.1); }
        #dateDisplay {
            min-width: 100px;
            text-align: center;
            font-weight: bold;
            color: #ffd700;
            background: #222;
            border: 1px solid #444;
            padding:0px 3px;
            border-radius: 4px;
            cursor: pointer;
        }
        #refreshBtn {
            padding: 4px 4px;
            background: #ffd700;
            color: #000;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-weight: bold;
        }
        .timeline {
            position: relative;
            max-width: 1200px;
            margin: 0 auto;
            padding: 0 0px;
            margin-top: 65px;
        }
        .timeline::before {
            content: '';
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            top: 0;
            bottom: 0;
            width: 4px;
            background: #ffd700;
            box-shadow: 0 0 10px #ffd700;
        }
        .timeline-item {
            position: relative;
            margin-bottom: 2px;
            display: flex;
            justify-content: space-between;
            width: 100%;
        }
        .time-marker.red { color: #ff0000; text-shadow: 0 0 8px #ff0000; }
        .time-marker.white { color: #ffffff; text-shadow: 0 0 8px #ffffff; }
        .time-marker.purple-red { color: #ff00ff; text-shadow: 0 0 8px #ff00ff; }
        .time-marker {
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            top: 0;
            width: 50px;
            text-align: center;
            font-size: 16px;
            font-weight: bold;
        }
        .left-panel,
        .right-panel {
            width: 45%;
            min-height: 20px;
            padding: 2px;
            background: #1a1a1a;
            border-radius: 6px;
            border: 1px solid #333;
        }
        .stock-item {
            display: grid;
            grid-template-columns: minmax(max-content, auto) minmax(max-content, auto) minmax(max-content, 1fr);
            gap: 2px;
            padding: 2px;
            margin: 2px 0;
            align-items: center;
            background: #2a2a2a;
            border-radius: 4px;
            border-left: 2px solid #ffd700;
        }
        .stock-name {
            font-weight: bold;
            white-space: nowrap;
            overflow: visible;
            text-overflow: clip;
            color: #ffd700;
            text-decoration: none;
            font-size: 14px;
            min-width: max-content;
        }
        .stock-name:hover {
            color: white;
            text-shadow: 0 0 8px #ffd700;
        }
        .board-status {
            text-align: center;
            color: #ffd700;
            font-size: 14px;
            padding: 1px 2px;
            border-radius: 3px;
            min-width: max-content;
        }

        .stock-item.has-yesterday {
            grid-template-columns: minmax(max-content, auto) minmax(max-content, auto) minmax(max-content, auto) minmax(max-content, 1fr);
        }
        .stock-item.has-fengdan {
            grid-template-columns: minmax(max-content, auto) minmax(max-content, auto) minmax(max-content, auto) minmax(max-content, 1fr);
        }
        .yesterday-dayb {
            font-size: 12px;
            color: #888;
            padding: 0 3px;
            min-width: 20px;
            text-align: center;
        }
        .reason-box {
            cursor: pointer;
            padding: 2px;
            border-radius: 3px;
            transition: all 0.3s;
            font-size: 12px;
            white-space: nowrap;
            overflow: visible;
            text-overflow: clip;
            background: rgba(255,255,255,0.1);
            min-width: max-content;
        }
        .fengdan-box {
            font-size: 12px;
            color: #ffd700;
            padding: 0 3px;
            text-align: right;
            min-width: max-content;
        }
        @keyframes glow {
            0% { box-shadow: 0 0 5px currentColor; }
            50% { box-shadow: 0 0 20px currentColor; }
            100% { box-shadow: 0 0 5px currentColor; }
        }
        input[type="date"]::-webkit-clear-button { display: none; }
    </style>
</head>
<body>
    <div class="controls">
        <div class="market-overview">
            <div class="stats-bar" id="statsBar">
                <div>板块：<span id="reasonCount">0</span></div>
                <div>连板：<span id="daybCount">0</span></div>
            </div>
            <div class="market-row" id="marketRow1"></div>
            <div class="market-row" id="marketRow2"></div>
            <div class="market-row" id="marketRow3"></div>
        </div>
        <div class="original-controls">
            <span class="type-label">
                炸板<span id="cztCount">0</span>|涨停<span id="ztCount">0</span>
            </span>
            <div class="date-nav">
                <button class="date-btn" id="prevDay">←</button>
                <input type="date" id="datePicker" hidden>
                <div id="dateDisplay">20240320周三</div>
                <button class="date-btn" id="nextDay">→</button>
            </div>
            <button id="refreshBtn">刷新</button>
        </div>
    </div>

    <div class="timeline" id="timeline"></div>

    <script>
        // 日期处理
        function getBeijingTime() {
            const now = new Date();
            const utc = now.getTime() + (now.getTimezoneOffset() * 60000);
            return new Date(utc + (3600000 * 8));
        }

        function isTradingDay() {
            const beijingDate = getBeijingTime();
            return beijingDate.getDay() >= 1 && beijingDate.getDay() <= 5;
        }

        function isTradingTime() {
            const beijingDate = getBeijingTime();
            const hours = beijingDate.getHours();
            const minutes = beijingDate.getMinutes();
            const time = hours * 100 + minutes;
            return (time >= 915 && time <= 1130) || (time >= 1300 && time <= 1500);
        }

        function getLastTradingDay(date = new Date()) {
            const checkDate = new Date(date);
            for(let i = 0; i < 14; i++) {
                if(checkDate.getDay() !== 0 && checkDate.getDay() !== 6) {
                    return new Date(checkDate);
                }
                checkDate.setDate(checkDate.getDate() - 1);
            }
            return new Date(date);
        }

        let lastValidTradingDay = null;
        let refreshInterval = null;

        function manageAutoRefresh() {
            const now = new Date();
            const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
            const validDay = getLastTradingDay(today).getTime() === today.getTime();
            
            const shouldRefresh = validDay && isTradingTime();
            if (shouldRefresh && !refreshInterval) {
                refreshInterval = setInterval(renderTimeline, 3000);
            } else if (!shouldRefresh && refreshInterval) {
                clearInterval(refreshInterval);
                refreshInterval = null;
            }
        }

        let currentDate = getLastTradingDay(new Date(new Date().setHours(0,0,0,0)));

        function formatDate(date) {
            const pad = n => n.toString().padStart(2, '0');
            return [
                date.getFullYear(),
                pad(date.getMonth() + 1),
                pad(date.getDate())
            ].join('');
        }

        function updateDateDisplay() {
            const pad = n => n.toString().padStart(2, '0');
            const weekdays = ['周日','周一','周二','周三','周四','周五','周六'];
            const year = currentDate.getFullYear();
            const month = pad(currentDate.getMonth() + 1);
            const day = pad(currentDate.getDate());
            const weekday = weekdays[currentDate.getDay()];
            document.getElementById('dateDisplay').textContent = `${year}${month}${day}${weekday}`;
            document.getElementById('datePicker').value = `${year}-${month}-${day}`;
        }



        async function fetchMarketData(date) {
            const aday = formatDate(date);
            try {
                const [marketRes, blockRes] = await Promise.all([
                    fetch(`https://data.10jqka.com.cn/mobileapi/hotspot_focus/market_state/v1/overview?date=${aday}`),
                    fetch(`https://goserver.huanshoulv.com/aimapp/surgeLimit/surgeTopBlock?date=${aday}&sort_field_name=surgedays&sort_type=-1&ts=1740497791359&sign=77e7a16f153f39995bdb487c3e0e79d4&appversion=2.0.0.6&has_dep=false&channel=hsl-app&div=ANDH020006`)
                ]);

                const [marketData, blockData] = await Promise.all([
                    marketRes.json(),
                    blockRes.json()
                ]);

                const rise = marketData.data.rise_fall.rise;
                const fall = marketData.data.rise_fall.fall;
                const deuce = marketData.data.rise_fall.deuce;
                const zt = marketData.data.rise_fall.limit_up;
                const dt = marketData.data.rise_fall.limit_down;
                const jcje = marketData.data.turnover.now;
                const zcje = marketData.data.turnover.pre;
                const jhb = marketData.data.limit_up.now;
                const zhb = marketData.data.limit_up.pre;

                const blocks = blockData.data.block.slice(0, 3)
                    .map(b => `${b.block_name} ${b.weight}`)
                    .join('  ');

                return { rise, fall, deuce, zt, dt, jcje, zcje, jhb, zhb, blocks };
            } catch (error) {
                console.error('市场数据加载失败:', error);
                return null;
            }
        }

        async function getHSL(aday) {
            try {
                const headers = new Headers({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36'});
                
                const mainUrl = `https://goserver.huanshoulv.com/aimapp/surgeLimit/surgeTopBlock?date=${aday}&sort_field_name=surgedays&sort_type=-1&ts=1740497791359&sign=77e7a16f153f39995bdb487c3e0e79d4&appversion=2.0.0.6&has_dep=false&channel=hsl-app&div=ANDH020006`;
                const mainRes = await fetch(mainUrl, {headers});
                const mainData = await mainRes.json();
                
                const stocks = {};
                const blocks = mainData.data.block;

                for (const block of blocks) {
                    const bkname = encodeURIComponent(block.block_name);
                    const bkzt = block.weight;
                    
                    const blockUrl = `https://goserver.huanshoulv.com/aimapp/surgeLimit/surgeTopBlock?date=${aday}&sort_field_name=surgedays&block_name=${bkname}&sort_type=-1&ts=1740497791359&sign=77e7a16f153f39995bdb487c3e0e79d4&appversion=2.0.0.6&has_dep=false&channel=hsl-app&div=ANDH020006`;
                    
                    const blockRes = await fetch(blockUrl, {headers});
                    const blockData = await blockRes.json();
                    
                    blockData.data.surgeList.forEach(asure => {
                        const code = asure[0];
                        const fdl = asure[7];
                        const nowc = asure[3];
                        const fdValue = fdl * nowc;
                        
                        stocks[code] = {
                            concept: block.block_name,
                            lb: asure[26],
                            fd: fdValue > 100000000 
                                ? `${(fdValue/100000000).toFixed(2)}亿`
                                : `${Math.round(fdValue/10000)}万`
                        };
                    });
                }
                return stocks;
            } catch (error) {
                console.error('HSL数据获取失败:', error);
                return {};
            }
        }

    async function getHSLztyy(aday) {
        try {
            const headers = new Headers({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36'});
            const url1 = `http://goserver.huanshoulv.com/aimapp/surgeLimit/surgeLimitList?date=${aday}&page=1&type=1&sort_type=-1&page_count=5000&channel=hsl-app&ts=1560867041083&sign=8e4ef91d04fca0817e2b21e9c816f14e`;
            const url2 = `http://goserver.huanshoulv.com/aimapp/surgeLimit/surgeLimitList?date=${aday}&page=1&type=2&sort_type=-1&page_count=5000&channel=hsl-app&ts=1560867041083&sign=8e4ef91d04fca0817e2b21e9c816f14e`;
            
            const [res1, res2] = await Promise.all([fetch(url1, {headers}), fetch(url2, {headers})]);
            const data1 = await res1.json();
            const data2 = await res2.json();
            
            const list = [...data1.data.surgeList, ...data2.data.surgeList];
            const hslztyy = {};
            
            function parseReason(str) {
                const matchPlus = str.match(/\+(.*?)\（/);
                if (matchPlus) return matchPlus[1];
                const matchStart = str.match(/^(.*?)\（/);
                return matchStart ? matchStart[1] : null;
            }

            list.forEach(item => {
                const code = item[32];
                const reason = parseReason(item[3]) || '未知概念';
                hslztyy[code] = reason;
            });
            return hslztyy;
        } catch (error) {
            console.error('HSL涨停原因获取失败:', error);
            return {};
        }
    }





        // 主数据接口
        async function fetchData(date) {
            const currentDateObj = new Date(date);
            const formattedDate = formatDate(currentDateObj);
            
            // 获取昨日数据
            const prevDateObj = new Date(currentDateObj);
            prevDateObj.setDate(prevDateObj.getDate() -1);
            const prevDate = getLastTradingDay(prevDateObj);
            const prevFormattedDate = formatDate(prevDate);

            try {
                    const [ztRes, cztRes, hslData, hslztyyData, prevRes] = await Promise.all([
                    fetch(`https://api.duishu.com//lhbapp/zhangting/index?day=${formattedDate}&pagecount=20&position=2&page=1&type=1&orderKey=zt_time&orderValue=desc&apiversion=8.9`),
                    fetch(`https://api.duishu.com//lhbapp/zhangting/index?day=${formattedDate}&pagecount=20&page=1&type=2&apiversion=8.9`),
                    getHSL(formattedDate),
                    getHSLztyy(formattedDate),
                    fetch(`https://api.duishu.com//lhbapp/zhangting/index?day=${prevFormattedDate}&pagecount=200&position=2&page=1&type=1&orderKey=zt_time&orderValue=desc&apiversion=8.9`)
                ]);

                const [ztData, cztData, prevData] = await Promise.all([
                    ztRes.json(),
                    cztRes.json(),
                    prevRes.json().catch(() => ({ data: { stock_list: { list: [] }}})) // 容错处理
                ]);

                const prevDaybMap = prevData.data.stock_list.list.reduce((acc, item) => {
                    const code = item[0].text.split('#')[1];
                    acc[code] = item[3].text.replace('连', '').replace('首', '1');
                    return acc;
                }, {});

                const processItems = (items, isZt) => items.map(item => {
                    const code = item[0].text.split('#')[1];
                    let reason = hslData[code]?.concept || '未知概念';
                    if (reason === '未知概念' && hslztyyData[code]) {
                        reason = hslztyyData[code];
                    }
                    return {
                        time: item[2].text,
                        name: item[0].text.split('#')[0],
                        code: code,
                        zf: item[1].text,
                        reason: reason,
                        dayb: item[3].text.replace('连', '').replace('首', '1'),
                        prev_dayb: prevDaybMap[code] || '-',
                        fengdan: item[5].text,
                        type: isZt ? 'zt' : 'czt'
                    };
                });

                return [
                    ...processItems(ztData.data.stock_list.list, true),
                    ...processItems(cztData.data.stock_list.list, false)
                ];
            } catch (error) {
                console.error('数据获取失败:', error);
                return [];
            }
        }

        function createStockItem(item, isCzt) {
            const div = document.createElement('div');
            div.className = `stock-item ${isCzt ? 'has-yesterday' : 'has-fengdan'}`;
            div.innerHTML = `
                <a class="stock-name" href="http://www.treeid/code_${item.code}">
                    ${item.name}
                </a>
                <div class="board-status selectable"
                     data-dayb="${item.dayb}"
                     style="--hue:${Math.random() * 360}">
                    ${isCzt ? item.zf : item.dayb}
                </div>
                ${isCzt ? `
                <div class="yesterday-dayb" title="昨日连板天数">
                    ${item.prev_dayb}
                </div>
                ` : ''}
                <div class="reason-box selectable"
                     data-reason="${item.reason}"
                     style="--hue:${Math.random() * 360}">
                    ${item.reason}
                </div>
                ${!isCzt ? `
                <div class="fengdan-box" title="封单金额">
                    ${item.fengdan}
                </div>
                ` : ''}
            `;
            return div;
        }

        async function renderTimeline() {
            currentDate = getLastTradingDay(currentDate);
            try {
                const marketData = await fetchMarketData(currentDate);
                if (marketData) {
                    const jcjeNum = parseFloat(marketData.jcje.replace(/,/g, '')) || 0;
                    const zcjeNum = parseFloat(marketData.zcje.replace(/,/g, '')) || 0;
                    const jhbNum = parseInt(marketData.jhb) || 0;
                    const zhbNum = parseInt(marketData.zhb) || 0;

                    document.getElementById('marketRow1').innerHTML = `
                        <span>上涨<span class="red">${marketData.rise}</span>
                        下跌<span class="green">${marketData.fall}</span>
                        平盘<span class="white">${marketData.deuce}</span>
                        涨停<span class="red">${marketData.zt}</span>
                        跌停<span class="green">${marketData.dt}</span>
                    `;

                    document.getElementById('marketRow2').innerHTML = `
                        <span>今额:<span class="${jcjeNum > zcjeNum ? 'red' : 'green'}">${marketData.jcje}</span>
                        昨额:<span class="white">${marketData.zcje}</span>
                        今板高<span class="${jhbNum > zhbNum ? 'red' : 'green'}">${marketData.jhb}</span>
                        昨板高<span class="white">${marketData.zhb}</span>
                    `;

                    document.getElementById('marketRow3').innerHTML = 
                        marketData.blocks.split('  ').map(b => 
                            `<span>${b.split(' ')[0]} <span class="highlight">${b.split(' ')[1]}</span></span>`
                        ).join('');
                }

                const data = await fetchData(currentDate);
                let ztCount = 0, cztCount = 0;
                const sortedData = data.sort((a, b) => {
                    const timeA = parseInt(a.time.replace(':', ''));
                    const timeB = parseInt(b.time.replace(':', ''));
                    return timeB - timeA;
                });

                const groupedData = sortedData.reduce((acc, item) => {
                    item.type === 'zt' ? ztCount++ : cztCount++;
                    acc[item.time] = acc[item.time] || { zt: [], czt: [] };
                    item.type === 'zt' ? acc[item.time].zt.push(item) : acc[item.time].czt.push(item);
                    return acc;
                }, {});

                document.getElementById('ztCount').textContent = ztCount;
                document.getElementById('cztCount').textContent = cztCount;

                const timeline = document.getElementById('timeline');
                timeline.innerHTML = '';
                Object.entries(groupedData).forEach(([time, items]) => {
                    const [hours, minutes] = time.split(':').map(Number);
                    const totalTime = hours * 100 + minutes;
                    
                    let timeColorClass = '';
                    if (totalTime < 1000) {
                        timeColorClass = 'red';
                    } else if (totalTime >= 1000 && totalTime < 1430) {
                        timeColorClass = 'white';
                    } else {
                        timeColorClass = 'purple-red';
                    }

                    const container = document.createElement('div');
                    container.className = 'timeline-item';
                    container.innerHTML = `
                        <div class="time-marker ${timeColorClass}">${time}</div>
                        <div class="left-panel">
                            ${items.czt.map(item => createStockItem(item, true).outerHTML).join('')}
                        </div>
                        <div class="right-panel">
                            ${items.zt.map(item => createStockItem(item, false).outerHTML).join('')}
                        </div>
                    `;
                    timeline.appendChild(container);
                });

                const restoreSelection = (storageKey, dataAttr) => {
                    const selections = JSON.parse(sessionStorage.getItem(storageKey) || '[]');
                    if (selections.length) {
                        requestAnimationFrame(() => {
                            let needUpdate = false;
                            selections.forEach(({ value, color }) => {
                                document.querySelectorAll(`[data-${dataAttr}="${value}"]`).forEach(box => {
                                    box.style.backgroundColor = color;
                                    box.style.color = '#000';
                                    box.style.fontWeight = 'bold';
                                    box.style.animation = 'glow 1.5s ease-in-out infinite';
                                    needUpdate = true;
                                });
                            });
                            if(needUpdate) updateCount();
                        });
                    }
                    updateCount();
                };

                restoreSelection('selections', 'reason');
                restoreSelection('daybSelections', 'dayb');
            } catch (error) {
                console.error('数据加载失败:', error);
            }
        }

        function updateCount() {
            const reasonCounts = {};
            document.querySelectorAll('.reason-box[data-reason]').forEach(item => {
                if (item.style.backgroundColor) {
                    const reason = item.dataset.reason.split(' ')[0];
                    reasonCounts[reason] = (reasonCounts[reason] || 0) + 1;
                }
            });
            
            const sortedReasons = Object.entries(reasonCounts)
                .sort((a, b) => b[1] - a[1])
                .slice(0, 5)
                .map(([k, v]) => `${k}${v}`);
            
            document.getElementById('reasonCount').textContent = sortedReasons.join(' ') || '0';

            const daybCounts = {};
            document.querySelectorAll('.board-status[data-dayb]').forEach(item => {
                if (item.style.backgroundColor) {
                    const dayb = item.dataset.dayb.replace('天', '');
                    daybCounts[dayb] = (daybCounts[dayb] || 0) + 1;
                }
            });
            const sortedDayb = Object.entries(daybCounts)
                .sort((a, b) => b[0].localeCompare(a[0]))
                .map(([k, v]) => `${k}${v}`);
            
            document.getElementById('daybCount').textContent = sortedDayb.join(' ') || '0';
        }

        document.getElementById('prevDay').addEventListener('click', () => {
            const originalDate = new Date(currentDate);
            if(originalDate.getDay() === 1) {
                currentDate = new Date(originalDate.setDate(originalDate.getDate() - 3));
            } else {
                currentDate = new Date(originalDate.setDate(originalDate.getDate() - 1));
            }
            currentDate = getLastTradingDay(currentDate);
            updateDateDisplay();
            renderTimeline();
        });

        document.getElementById('nextDay').addEventListener('click', () => {
            const originalDate = new Date(currentDate);
            if(originalDate.getDay() === 5) {
                currentDate = new Date(originalDate.setDate(originalDate.getDate() + 3));
            } else {
                currentDate = new Date(originalDate.setDate(originalDate.getDate() + 1));
            }
            currentDate = getLastTradingDay(currentDate);
            updateDateDisplay();
            renderTimeline();
        });

        document.getElementById('dateDisplay').addEventListener('click', () => {
            document.getElementById('datePicker').showPicker();
        });

        document.getElementById('datePicker').addEventListener('change', function() {
            const [year, month, day] = this.value.split('-');
            const selectedDate = new Date(year, month - 1, day);
            currentDate = getLastTradingDay(selectedDate);
            updateDateDisplay();
            renderTimeline();
        });

        document.getElementById('refreshBtn').addEventListener('click', renderTimeline);

        document.getElementById('timeline').addEventListener('click', (e) => {
            const target = e.target.closest('.selectable');
            if (!target) return;

            const isDayb = target.classList.contains('board-status');
            const storageKey = isDayb ? 'daybSelections' : 'selections';
            const dataAttr = isDayb ? 'dayb' : 'reason';

            const selections = JSON.parse(sessionStorage.getItem(storageKey) || '[]');
            const currentColor = `hsl(${target.style.getPropertyValue('--hue')},100%,50%)`;
            const value = target.dataset[dataAttr];

            const existingIndex = selections.findIndex(s => s.value === value);
            if (existingIndex >= 0) {
                selections.splice(existingIndex, 1);
                document.querySelectorAll(`[data-${dataAttr}="${value}"]`).forEach(el => {
                    el.style.backgroundColor = '';
                    el.style.color = '';
                    el.style.animation = '';
                });
            } else {
                if (selections.length >= 200) selections.shift();
                selections.push({ value, color: currentColor });
                document.querySelectorAll(`[data-${dataAttr}="${value}"]`).forEach(el => {
                    el.style.backgroundColor = currentColor;
                    el.style.color = '#000';
                    el.style.fontWeight = 'bold';
                    el.style.animation = 'glow 1.5s ease-in-out infinite';
                });
            }
            sessionStorage.setItem(storageKey, JSON.stringify(selections));
            updateCount();
        });

        updateDateDisplay();
        renderTimeline();
        setInterval(manageAutoRefresh, 60000);
        manageAutoRefresh();
    </script>
</body>
</html>